/*
 * @Author: AiLjx
 * @Date: 2022-11-24 16:15:31
 * @LastEditors: AiLjx
 * @LastEditTime: 2022-11-28 21:48:21
 */
// creates a global "addWheelListener" method
// example: addWheelListener( elem, function( e ) { console.log( e.deltaY ); e.preventDefault(); } );
(function (window, document) {
    var prefix = "",
        _addEventListener,
        onwheel,
        support;

    // detect event model
    if (window.addEventListener) {
        _addEventListener = "addEventListener";
    } else {
        _addEventListener = "attachEvent";
        prefix = "on";
    }

    // detect available wheel event
    support =
        "onwheel" in document.createElement("div")
            ? "wheel" // 各个厂商的高版本浏览器都支持"wheel"
            : document.onmousewheel !== undefined
            ? "mousewheel" // Webkit 和 IE 一定支持"mousewheel"
            : "DOMMouseScroll"; // 低版本 firefox

    window.addWheelListener = function (elem, callback, useCapture) {
        _addWheelListener(elem, support, callback, useCapture);

        // handle MozMousePixelScroll in older Firefox
        if (support == "DOMMouseScroll") {
            _addWheelListener(
                elem,
                "MozMousePixelScroll",
                callback,
                useCapture
            );
        }
    };

    function _addWheelListener(elem, eventName, callback, useCapture) {
        elem[_addEventListener](
            prefix + eventName,
            support == "wheel"
                ? callback
                : function (originalEvent) {
                      !originalEvent && (originalEvent = window.event);

                      // create a normalized event object
                      var event = {
                          // keep a ref to the original event object
                          originalEvent: originalEvent,
                          target:
                              originalEvent.target || originalEvent.srcElement,
                          type: "wheel",
                          deltaMode:
                              originalEvent.type == "MozMousePixelScroll"
                                  ? 0
                                  : 1,
                          deltaX: 0,
                          deltaZ: 0,
                          preventDefault: function () {
                              originalEvent.preventDefault
                                  ? originalEvent.preventDefault()
                                  : (originalEvent.returnValue = false);
                          },
                      };

                      // calculate deltaY (and deltaX) according to the event
                      if (support == "mousewheel") {
                          event.deltaY = (-1 / 40) * originalEvent.wheelDelta;
                          // Webkit also support wheelDeltaX
                          originalEvent.wheelDeltaX &&
                              (event.deltaX =
                                  (-1 / 40) * originalEvent.wheelDeltaX);
                      } else {
                          event.deltaY = originalEvent.detail;
                      }

                      // it's time to fire the callback
                      return callback(event);
                  },
            useCapture || false
        );
    }
})(window, document);

/**
 * 在指定容器中生成歌词滚动
 * @param {string} container 全局容器选择器
 * @param {string} ul 歌词容器选择器
 * @param {string} audio audio标签选择器
 * @param {string} words 歌词字符串
 */
class LyricsControl {
    #con;
    #conHeight;
    #ul;
    #audio;
    #wordsArr;
    #liHeight;
    #isRoll;
    #translateY;
    #isWheel;
    #wheelFnTimer;
    constructor(container, audio, words) {
        // 最外层容器dom
        this.#con = document.querySelector(container);
        // 容器高度
        this.#conHeight = this.#con.clientHeight;
        // 歌词容器
        this.#ul = null;
        // 播放器dom
        this.#audio = document.querySelector(audio);
        // 获取歌词对象
        this.#wordsArr = this.#parseLrc(words);
        // 每句歌词的高度
        this.#liHeight = 0;
        // 是否启用
        this.#isRoll = false;
        // 歌词UI容器纵向偏移量 ，取值范围：大于0 小于Ui高度-con高度
        this.#translateY = 0;
        // 是否正在滚动
        this.#isWheel = false;
        this.#wheelFnTimer = null;
        this.#listenEvent();
    }
    get isRoll() {
        return this.#isRoll;
    }
    // 歌词容器最大偏移量
    get #maxTranslateY() {
        return this.#ul.clientHeight - this.#conHeight;
    }
    // 各种监听事件
    #listenEvent() {
        // 监听鼠标滚轮事件
        addWheelListener(
            this.#con,
            throttle((e) => {
                this.#WheelFn(this.#translateY + e.deltaY);
            }, 50)
        );
        // 监听移动端滑动事件
        let startY = 0, // 触控点的起始位置
            startTranslateY = 0; // 触控时的translateY
        this.#con.addEventListener("touchstart", (e) => {
            startY = e.changedTouches[0].clientY;
            startTranslateY = this.#translateY;
        });
        this.#con.addEventListener(
            "touchmove",
            throttle((e) => {
                let j = startY - e.changedTouches[0].clientY;
                this.#WheelFn(startTranslateY + j);
            }, 20)
        );
    }
    // 鼠标滚轮滚动/移动端滑动事件
    #WheelFn(newtranslatey) {
        this.#isWheel = true;
        if (this.#wheelFnTimer !== null) {
            clearTimeout(this.#wheelFnTimer);
        }
        this.#setTranslateY(newtranslatey);
        // 滚动一秒后重置isWheel，恢复歌词自动滚动
        this.#wheelFnTimer = setTimeout(() => {
            this.#isWheel = false;
        }, 1000);
    }
    // 设置歌词容器纵向偏移量
    #setTranslateY(Y) {
        // 取值范围：大于0 小于Ui高度-con高度
        if (Y < 0) {
            this.#translateY = 0;
        } else if (Y > this.#maxTranslateY) {
            this.#translateY = this.#maxTranslateY;
        } else {
            this.#translateY = Y;
        }
        // 应用偏移
        this.#ul.style.transform = `translateY(${-this.#translateY}px)`;
    }
    /**
     * 解析歌词字符串，获取歌词对象集合
     * @param {string} lyric 歌词字符串
     * @return {Array<object>} 歌词对象集合
     */
    #parseLrc(lyric) {
        let lrcArr = lyric.split("\n");
        let result = [];
        for (const item of lrcArr) {
            let itemArr = item.split("]");
            // console.log(itemArr);
            if (itemArr[1] && itemArr[1].trim()) {
                result.push({
                    time: this.#parseTime(itemArr[0].substring(1)),
                    words: itemArr[1].trim(),
                });
            }
        }
        return result;
    }

    /**
     * 转换时间格式
     * @param {string} timeStr 时间字符串 例：00:04.050
     * @return {number} 秒数 例：4.05
     */
    #parseTime(timeStr) {
        let strArr = timeStr.split(":");
        return +strArr[0] * 60 + +strArr[1];
    }

    // 创建歌词元素 li
    #createLrcElement() {
        this.#ul = document.createElement("ul");
        this.#ul.setAttribute("id", "lrc-list");
        let fm = document.createDocumentFragment(); // 文档片段
        for (let i = 0; i < this.#wordsArr.length; i++) {
            let li = document.createElement("li");
            li.textContent = this.#wordsArr[i].words;
            fm.appendChild(li);
        }
        this.#ul.appendChild(fm);
        this.#con.appendChild(this.#ul);
    }

    /**
     * 查找正在播放的当前歌词下标
     * @return {number} index 歌词对应的下标
     */
    #findIndex() {
        let currentTime = this.#audio.currentTime;
        for (let i = 0; i < this.#wordsArr.length; i++) {
            if (this.#wordsArr[i].time > currentTime) {
                return i === 0 ? i : i - 1;
            }
        }
        return this.#wordsArr.length - 1;
    }

    // 移动歌词动画效果
    #setOffset = () => {
        const active = document.querySelector(".active");
        const index = this.#findIndex();
        const target = this.#ul.children[index];

        if (active !== target) {
            active && active.classList.remove("active");
            target.classList.add("active");
        }

        if (!this.#isWheel) {
            this.#setTranslateY(
                (index + 1) * this.#liHeight - this.#conHeight / 2
            );
        }
    };

    // 启动歌词滚动
    play() {
        // 创建并添加li
        this.#createLrcElement();
        // 获取li高度
        this.#liHeight = this.#ul.children[0].clientHeight;
        // 监听audio播放进度
        this.#audio.addEventListener("timeupdate", this.#setOffset, false);
        this.#isRoll = true;
    }

    // 清除歌词滚动
    clear() {
        this.#ul.innerHTML = "";
        this.#audio.removeEventListener("timeupdate", this.#setOffset, false);
        this.#isRoll = false;
    }
}

/**
 * 封装节流函数
 * @param {Function} fn 原函数
 * @param {Number} delay 节流时间
 * @return {Function} throttleFn 节流函数
 */
function throttle(fn, delay = 0) {
    let throttleTimer = null;
    return (...args) => {
        if (throttleTimer !== null) {
            return;
        }
        fn(...args);
        throttleTimer = setTimeout(() => {
            throttleTimer = null;
        }, delay);
    };
}
